package cn.kgc.security;

import cn.kgc.entity.CustomerUser;
import cn.kgc.entity.Users;
import cn.kgc.form.LoginForm;
import cn.kgc.util.JwtUtil;
import cn.kgc.util.ResponseUtil;
import cn.kgc.util.resultutil.Result;
import cn.kgc.util.resultutil.ResultConstant;
import cn.kgc.util.resultutil.exception.HttpException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * @author YC
 * 登录认证的过滤器
 */
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private final JwtUtil jwtUtil;

    /**
     * 登录认证的过滤器构造方法（之后自己创建实例使用，没有交给Spring容器管理）
     */
    public AuthenticationFilter(AuthenticationManager authenticationManager, JwtUtil jwtUtil) {
        // 设置认证管理器
        this.setAuthenticationManager(authenticationManager);
        this.jwtUtil = jwtUtil;
        // 指定登录请求是否只支持post请求
        this.setPostOnly(false);
        // 指定登录请求路径
        this.setRequiresAuthenticationRequestMatcher(
                new AntPathRequestMatcher("/users/login", "POST")
        );
    }

    /**
     * 登录认证
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            // 从请求中获得loginForm对象
            LoginForm loginForm = new ObjectMapper().readValue(request.getInputStream(), LoginForm.class);
            // 将loginForm对象封装到Authentication对象中
            Authentication authentication = new UsernamePasswordAuthenticationToken(
                    loginForm.getUserName(),
                    loginForm.getPassword()
            );
            // 调用认证管理器中的方法进行认证
            return getAuthenticationManager().authenticate(authentication);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 登录成功的方法
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {

        // 获得登录成功的用户信息
        CustomerUser customerUser = (CustomerUser) authResult.getPrincipal();
        Users users = customerUser.getUsers();
        // 判断用户的状态，离职状态抛出异常
        if (customerUser.getUsers().getState() == cn.kgc.util.SystemConstant.USER_STATE_RESIGN) {
            // 数据库设计2为离职
            ResponseUtil.setResponse(response, Result.error(new HttpException(ResultConstant.LOGIN_ERROR)));
        }
        // 在职状态（试用期和转正）生成token令牌 将用户的id、名字返回
        Integer userId = customerUser.getUsers().getUserId();
        String token = jwtUtil.generateAccessToken(userId.toString());
        Map<String, Object> map = Map.of("userId", userId, "userName", users.getUserName(), "token", token);
        ResponseUtil.setResponse(response, Result.success(map));
    }

    /**
     * 登录失败的方法
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        // 登录失败抛出异常
        ResponseUtil.setResponse(response, Result.error(new HttpException(ResultConstant.LOGIN_ERROR)));
    }

}
